/***************************************************************************
  * 
  * Homework for chapter 3 -- "overlap-save method"
  *
  * Here is the realization of add rir function.
  * You have to finish "conv" function by yourself. It is called in main 
  * function. Also, you may want to use FFT, which is ready for you too.
  *
  * NOTICE: There is no IFFT function. So you have to realize IFFT using FFT.
  * Take some time to think about how to do this please.
  * 
  **************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "conv.h"
#include "baselib.h"
#include <iostream>

template<typename T>
void convert_to_complex(COMPLEX* inputdata_com, T* inputdata, long inputdata_length){

    for (int i=0; i< inputdata_length; ++i){
        inputdata_com[i].real = float (inputdata[i]);
        inputdata_com[i].image = 0.0;
    }
}

void complex_times(COMPLEX &x, COMPLEX &y, COMPLEX &ans){
    ans.real = x.real * y.real - x.image * y.image;
    ans.image = x.image * y.real + x.real * y.image;
}

/**
 * @brief add rir using overlap-save method.
 *
 * @param inputdata         input clean audio data buffer
 * @param inputdata_length  length of inputdata(samples)
 * @param rir               room impulse response buffer
 * @param rir_length        length of rir, 4096 by default
 * @param outputdata        processed data, same length as inputdata
 * @return 
 *     @retval 0            successfully
 */
int conv(short* inputdata, long inputdata_length, double* rir, long rir_length, short* outputdata)
{
    // finish overlap-save method here

    int block_size = rir_length<<1;
    int fftorder = log2(block_size);

    COMPLEX rir_com[block_size];
    convert_to_complex(rir_com, rir, rir_length);
    for (int i = rir_length; i < block_size; ++i) {
        rir_com[i].real = 0, rir_com[i].image = 0;
    }
    fft(rir_com, fftorder);

    COMPLEX inputdata_com[block_size];
    COMPLEX outputdata_com[block_size];
    for (int i = 0; i < inputdata_length; i+=rir_length) {

        if(i+block_size < inputdata_length){
            convert_to_complex(inputdata_com, inputdata+i, block_size);
        } else{
            convert_to_complex(inputdata_com, inputdata+i, inputdata_length-i-1);
            for (int j = inputdata_length-i; j < block_size; ++j) {
                inputdata_com[j].real = 0, inputdata_com[j].image = 0;
            }
        }

        fft(inputdata_com, fftorder);
        for (int j = 0; j < block_size; ++j) {
            int r, i;
            r = inputdata_com[j].real * rir_com[j].real - inputdata_com[j].image * rir_com[j].image;
            i = inputdata_com[j].image * rir_com[j].real + inputdata_com[j].real * rir_com[j].image;
            outputdata_com[j].real = r;
            outputdata_com[j].image = i;
        }
        ifft(outputdata_com, fftorder);

        for (int j = 0; j < rir_length; ++j) {
            outputdata[i+j] = outputdata_com[rir_length+j-1].real;
        }

    }

    return 0;
}

//直接卷积
int my_conv(short* inputdata, long inputdata_length, double* rir, long rir_length, short* outputdata){

    memset(outputdata, 0, inputdata_length);
    for (int i = 0; i < inputdata_length; ++i) {
        for (int j = 0; j < rir_length && i+j <inputdata_length; ++j) {
            outputdata[i+j] += inputdata[i] * rir[j];
        }
    }

    return 0;
}


/* vim: set expandtab ts=4 sw=4 sts=4 tw=100: */
